package com.xyz.app.shiro;

import com.free.ext.logger.FreeLogger;
import com.free.ext.logger.FreeLoggerFactory;
import com.free.utils.HttpUtils;
import com.free.utils.enums.ENUM_DEVICE_TYPE;
import com.xyz.app.constants.ShiroConstants;
import com.xyz.domain.table.CCustomer;
import com.xyz.service.CustomerService;
import com.xyz.shiro.BasicShiroFilter;
import com.xyz.utils.ThreadLocalUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.cache.ehcache.EhCacheCacheManager;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

public class JwtShiroFilter extends BasicShiroFilter {

    private static FreeLogger LOGGER = FreeLoggerFactory.getLogger(JwtShiroFilter.class);

    CustomerService customerService;
    EhCacheCacheManager ehCacheCacheManager;

    public JwtShiroFilter(CustomerService customerService, EhCacheCacheManager ehCacheCacheManager){
        this.customerService = customerService;
        this.ehCacheCacheManager = ehCacheCacheManager;
    }

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        String tokenStr = getHeaderInfo(WebUtils.toHttp(request),ShiroConstants.TOKEN_HEADER_NAME);
        if(StringUtils.isNotEmpty(tokenStr)){
            try{
                this.executeLogin(request, response);
            }catch (Exception ex){
                LOGGER.info("用户登录时发生异常{}",ex);
                return  false;
            }
        }else{
            // 没有携带Token
            HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
            // 获取当前请求类型
            String httpMethod = httpServletRequest.getMethod();
            // 获取当前请求URI
            String requestURI = httpServletRequest.getRequestURI();
            LOGGER.info("当前请求 {} Authorization属性(Token)为空 请求类型 {}", requestURI, httpMethod);
            return false;
        }
        return true;
    }

    @Override
    public boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        response401(servletRequest, servletResponse);
        fillCorsHeader(WebUtils.toHttp(servletRequest), WebUtils.toHttp(servletResponse));
        return false;
    }

    @Override
    public void loginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) {
        ENUM_DEVICE_TYPE deviceType = HttpUtils.getDeviceType(WebUtils.toHttp(request));
        String newToken = null;
        if(token instanceof JwtToken){
            JwtToken jwtToken = (JwtToken)token;
            CCustomer user = (CCustomer) subject.getPrincipal();
            newToken = customerService.refershToken(jwtToken.getPrincipal().toString(), user.getUserName(), String.valueOf(deviceType.getKey()));
            setLocal(user);
        }
        if(StringUtils.isNotBlank(newToken))
            setHeader(WebUtils.toHttp(response),ShiroConstants.TOKEN_HEADER_NAME,newToken);
    }


    @Override
    public void loginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        throw e;
    }


    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        String tokenStr = getHeaderInfo(WebUtils.toHttp(servletRequest),ShiroConstants.TOKEN_HEADER_NAME);
        return new JwtToken(tokenStr);
    }

    private void setLocal(CCustomer account){
        Map<String,Object> params = new HashMap<>();
        params.put(ThreadLocalUtils.ACCOUNT,account);
        ThreadLocalUtils.put(params);

    }


}
